﻿#include "OperGmshGenerator.h"
#include "FITK_Kernel/FITKAppFramework/FITKGlobalData.h"
#include "FITK_Kernel/FITKAppFramework/FITKAppFramework.h"
#include "FITK_Kernel/FITKAppFramework/FITKAppSettings.h"
#include "FITK_Kernel/FITKAppFramework/FITKComponents.h"
#include "FITK_Kernel/FITKAppFramework/FITKMessage.h"
#include "OperatorsInterface/GraphEventOperator.h"
#include "GUIFrame/MainWindow.h"
#include "GUIWidget/ControlPanel.h"
#include "FITK_Kernel/FITKCore/FITKDirFileTools.h"
#include "OperatorsInterface/TreeEventOperator.h"
//#include "FITK_Kernel/FITKCore/FITKAbstractDataManager.hpp"
#include "FITK_Interface/FITKInterfaceGeometry/FITKGeoInterfaceFactory.h"
//#include "FITK_Interface/FITKInterfaceGeometry/FITKAbsGeoModelExport.h"
#include "FITK_Interface/FITKInterfaceGeometry/FITKAbsGeoModelExportTopos.h"
#include "FITK_Interface/FITKInterfaceMeshGen/FITKMeshGenInterface.h"
#include "FITK_Interface/FITKInterfaceMeshGen/FITKAbstractMesherDriver.h"
#include "FITK_Interface/FITKInterfaceMeshGen/FITKAbstractMeshProcessor.h"
#include "FITK_Interface/FITKInterfaceMeshGen/FITKGlobalMeshGenerateAlgorithmInfo.h"
#include "FITK_Interface/FITKInterfaceMesh/FITKUnstructuredMeshVTK.h"
#include "FITK_Component/FITKGmshExeDriver/FITKMeshGenGmshExecInterface.h"
#include "FITK_Interface/FITKInterfaceModel/FITKComponentManager.h"
#include "FITK_Component/FITKRadiossData/FITKRadiossCase.h"
#include "FITK_Component/FITKRadiossData/FITKRadiossMeshModel.h"
#include "FITK_Component/FITKRadiossData/FITKRadiossNodesParts.h"
#include "FITK_Kernel/FITKCore/FITKVec3D.h"
#include "FITK_Interface/FITKInterfaceModel/FITKAbstractElement.h"
#include "FITK_Interface/FITKInterfaceModel/FITKElementFactory.h"
#include "FITK_Interface/FITKInterfaceGeometry/FITKGeoCommandList.h"
#include "FITK_Component/FITKGmshExeDriver/GUIGmshSettings.h"

#include <QDir>
#include <QDateTime>
#include <QMessageBox>
#include <QHash>

namespace ModelOper
{
    bool OperGmshGenerator::execGUI()
    {
        //获取动作名称
        QString actionName = _emitter->objectName();
        QWidget* mw = FITKAPP->getGlobalData()->getMainWindow();
        if (!mw) return false;
        if (actionName == "actionGmshSettings")
        {
            GUI::GUIGmshSettings* dialog = new GUI::GUIGmshSettings(this, mw);
            dialog->isEnableGeometryStitch(true);
            //当界面执行完毕后执行
            connect(dialog, &QDialog::accepted, this, &OperGmshGenerator::execProfession);
            dialog->show();
        }
        return false;
    }

    bool OperGmshGenerator::execProfession()
    {
        int dim = -1;
        this->argValue("dim", dim);
        QVariant v = {};
        this->argValue("virtualTopos", v);
        QList<Interface::VirtualShape> topos = v.value<QList<Interface::VirtualShape>>();
        if (topos.size() == 0)return false;

        //获取工作目录
        QString meshPath = FITKAPP->getTempDir(false, "Gmsh");
        //网格划分路径指定
        QString shapeFile = meshPath + "/geometryFile.stp";
        QString meshFile = QString("%1/%2").arg(meshPath).arg("mesh.msh");
        QString scriptFile = QString("%1/%2").arg(meshPath).arg("script.geo");
        QDir meshDir(meshPath);
        if (!meshDir.exists())
        {
            meshDir.mkdir(meshPath);
        }
        Core::ClearDir(meshPath);
        if (shapeFile.isEmpty()) return false;
        //获取网格划分接口
        Interface::FITKMeshGenInterface* mf = Interface::FITKMeshGenInterface::getInstance();
        if (!mf) return false;
        Interface::FITKGlobalMeshGenerateAlgorithmInfo* meshGenAlgInfo = mf->getGlobalMeshGenerateAlgorithmInfo("GmshExec");
        if (!meshGenAlgInfo) return false;

        //获取几何文件生成工具
        Interface::FITKInterfaceGeometryFactory* geoFactory = Interface::FITKInterfaceGeometryFactory::getInstance();
        if (!geoFactory) return false;
        Interface::FITKAbsGeoModelExportTopos* geoExport = dynamic_cast<Interface::FITKAbsGeoModelExportTopos*>
            (geoFactory->createCommand(Interface::FITKGeoEnum::FITKGeometryComType::FGTExportTopos));
        if (!geoExport) return false;
        geoExport->setEnableStitch(meshGenAlgInfo->getGeometryStitch());
        geoExport->setExportTopos(topos);
        geoExport->setFileName(shapeFile);
        if (geoExport->update() == false) return false;

        //获取网格划分驱动
        Interface::FITKAbstractMesherDriver* mesher = mf->getMesherDriver("GmshExec");
        if (!mesher) return false;
        //取消关联信号
        disconnect(mesher, SIGNAL(mesherFinished()), nullptr, nullptr);
        connect(mesher, SIGNAL(mesherFinished()), this, SLOT(meshGenFinished()));
        //设置参数
        mesher->setValue("ShapeFile", shapeFile);
        mesher->setValue("MeshFile", meshFile);
        mesher->setValue("ScriptFile", scriptFile);
        meshGenAlgInfo->setMeshGenerateDimension(dim);
        //开始划分网格
        mesher->startMesher();
        this->setArgs("MeshFile", meshFile);

        return true;
    }

    void OperGmshGenerator::meshGenFinished()
    {
        QString meshFile = {};
        //获取网格文件，并判断是否生成成功
        if (!this->argValue<QString>("MeshFile", meshFile) || !QFileInfo(meshFile).isFile())
        {
            QMessageBox::warning(FITKAPP->getGlobalData()->getMainWindow(), tr("warning"), tr("Err! Mesher ProgramExec generate meshes failed."), QMessageBox::StandardButton::Ok);
            return;
        }
        //获取网格划分接口
        Interface::FITKMeshGenInterface* mf = Interface::FITKMeshGenInterface::getInstance();
        if (!mf) return;
        Interface::FITKAbstractMeshProcessor* processorMesh = mf->getMeshProcessor("GmshExec");
        if (!processorMesh) return;
        processorMesh->setValue("File", meshFile);
        //创建网格数据
        Interface::FITKUnstructuredMesh* mesh = new Interface::FITKUnstructuredMesh;
        Interface::FITKComponentManager* comp = new Interface::FITKComponentManager;
        //网格数据填充
        processorMesh->insertDataObject("Mesh", mesh);
        processorMesh->insertDataObject("ComponentManager", comp);
        processorMesh->setValue("LowDimElement", true);
        //调用网格处理接口
        processorMesh->start(QStringList() << "MSH");
        AppFrame::FITKMessageNormal(QString("Read file succeed:%1 %2").arg(meshFile).arg(QDateTime::currentDateTime().toString("yyyy-MM-dd hh:mm:ss:zzz")));

        Radioss::FITKRadiossCase* radiossCase = FITKAPP->getGlobalData()->getPhysicsData<Radioss::FITKRadiossCase>();
        if (!radiossCase) return;
        Radioss::FITKRadiossMeshModel* radiossMeshModel = radiossCase->getMeshModel();
        if (!radiossMeshModel) return;
        Radioss::FITKRadiossNodes* radiossNodes = radiossMeshModel->getNodes();
        if (!radiossNodes) return;
        Radioss::FITKRadiossPartManager* radiossPartManager = radiossMeshModel->getPartsManager();
        if (!radiossPartManager) return;
        Radioss::FITKRadiossPart* radiossPart = new Radioss::FITKRadiossPart;
        //将mesh中的网格数据填充至RadiossMeshModel
        const int nodeNum = mesh->getNodeCount();
        const int elementNum = mesh->getElementCount();
        QHash<int, int> nodeIdHash;
        //遍历node列表
        for (int i = 0; i < nodeNum; i++)
        {
            Core::FITKNode* node = mesh->getNodeAt(i);
            int nodeId = node->getNodeID();
            int newNodeID = radiossNodes->addNode(node->x(), node->y(), node->z());
            //将nodeID做映射
            nodeIdHash.insert(nodeId, newNodeID);
        }
        //遍历element列表
        for (int i = 0; i < elementNum; i++)
        {
            Interface::FITKAbstractElement* ele = mesh->getElementAt(i);
            if (ele == nullptr) continue;
            Interface::FITKModelEnum::FITKEleType type = ele->getEleType();
            //新建单元
            Interface::FITKAbstractElement* newElement = Interface::FITKElementFactory::createElement(type);
            if (newElement == nullptr) continue;
            QList<int> allnNodes = ele->getAllNodes();
            QList<int> newAllNodes{};
            for (int nodeId : allnNodes)
            {
                if (nodeIdHash.contains(nodeId))
                {
                    newAllNodes.append(nodeIdHash.value(nodeId));
                }
            }
            if (newElement->getNodeCount() != newAllNodes.size())
            {
                continue;
            }
            //添加映射后的节点ID
            newElement->setNodeID(newAllNodes);
            newElement->setEleID(ele->getEleID());
            radiossPart->addElement(newElement);
        }
        radiossPart->setDataObjectName(radiossPartManager->checkName(tr("Part-1")));
        radiossPartManager->appendDataObj(radiossPart);

        //释放暂存数据
        delete mesh;
        delete comp;

        // 通过树形菜单事件处理器刷新树
        QStringList listOpertor = { "TreeAssemblyEvent", "TreeGroupEvent" ,"TreePropertyEvent","TreeSolutionEvent" };
        for (int i = 0; i < listOpertor.size(); i++)
        {
            EventOper::TreeEventOperator* oper = dynamic_cast<EventOper::TreeEventOperator*>(Core::FITKOperatorRepo::getInstance()->getOperator(listOpertor[i]));
            if (oper != nullptr) oper->updateTree();
        }

        //更新渲染
        EventOper::GraphEventOperator* operGraph = FITKOPERREPO->getOperatorT<EventOper::GraphEventOperator>("GraphPreprocess");
        if (operGraph)
        {
            operGraph->updateGraph(radiossPart->getDataObjectID());
        }

        AppFrame::FITKMessageNormal(QString("Graph succeed:%1").arg(QDateTime::currentDateTime().toString("yyyy-MM-dd hh:mm:ss:zzz")));
    }
}
